﻿using System;
using System.Text;
namespace USArray
{
    struct StringBuilderNoGC
    {
        #region Init&Free
        StringNoGC buffer;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="capacity">//初始大小，合适的初始大小会减小扩容,扩容思路为 * 2。
        /// <param name="_nofree">true 则使用 temp 分配器，内存每帧会回收不用管</param>

        private StringBuilderNoGC(int capacity, bool _nofree = true)
        {
            buffer = StringNoGC.Create(capacity, _nofree);
        }
        public static StringBuilderNoGC Create(int capacity, bool _nofree = true)
        {
            return new StringBuilderNoGC(capacity, _nofree);
        }
        public void Free()
        {
            buffer.Free();
        }
        #endregion

        #region Reset&Append
        public void Reset()
        {
            unsafe
            {
                buffer.HeadPtr->length = 0;
            }
        }
        //StringBuilder 的核心思想就一个，自动扩容
        public unsafe void Unsafe_Append(char* str, int len)
        {
            var needlen = buffer.Length + len;
            if (needlen > buffer.MaxLength)//buf扩容
            {
                //计算新的capacity
                var newcapa = buffer.MaxLength * 2;//尝试x2
                if (newcapa < needlen)
                {
                    newcapa = needlen + buffer.MaxLength;//还是不够，就needlen+max
                }

                //产生newbuf
                var newbuf = StringNoGC.Create(newcapa, buffer.IsTemp);
                newbuf.CopyFrom(ref buffer);

                //交换
                buffer.Free();
                buffer = newbuf;
            }
            buffer.Unsafe_Concat(str, len);
        }
        public void Append(string str)
        {
            unsafe
            {
                fixed (char* str_ = str)
                {
                    Unsafe_Append(str_, str.Length);
                }
            }
        }

        public void Append(ref StringNoGC str)
        {
            unsafe
            {
                Unsafe_Append(str.CharPtr, str.Length);
            }
        }

        public void AppendLine(string str)
        {

            Append(str);
            Append("\n");
        }

        public void AppendLine(ref StringNoGC str)
        {
            Append(ref str);
            Append("\n");
        }
        public void AppendLine()
        {
            unsafe
            {
                Append("\n");
            }
        }
        #endregion

        #region AppendAny
        [ThreadStatic]
        static StringBuilder bridgesb;
        public void Append(char value, int repeatCount)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value, repeatCount);
            AppendStringBuilder(bridgesb);
        }
        public void Append(bool value)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value);
            AppendStringBuilder(bridgesb);
        }
        public void Append(char value)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value);
            AppendStringBuilder(bridgesb);
        }
        public void Append(ulong value)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value);
            AppendStringBuilder(bridgesb);
        }

        public void Append(uint value)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value);
            AppendStringBuilder(bridgesb);
        }
        public void Append(byte value)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value);
            AppendStringBuilder(bridgesb);
        }
        public void Append(string value, int startIndex, int count)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value, startIndex, count);
            AppendStringBuilder(bridgesb);
        }
        public void Append(float value)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value);
            AppendStringBuilder(bridgesb);
        }
        public void Append(ushort value)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value);
            AppendStringBuilder(bridgesb);
        }
        public void Append(char[] value)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value);
            AppendStringBuilder(bridgesb);
        }
        public void Append(char[] value, int startIndex, int charCount)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value, startIndex, charCount);
            AppendStringBuilder(bridgesb);
        }
        public void Append(sbyte value)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value);
            AppendStringBuilder(bridgesb);
        }
        public void Append(decimal value)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value);
            AppendStringBuilder(bridgesb);
        }
        public void Append(short value)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value);
            AppendStringBuilder(bridgesb);
        }
        public void Append(int value)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value);
            AppendStringBuilder(bridgesb);
        }
        public void Append(long value)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value);
            AppendStringBuilder(bridgesb);
        }
        public void Append(double value)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.Append(value);
            AppendStringBuilder(bridgesb);
        }

        public void AppendStringBuilder(StringBuilder sb)
        {
            var needlen = buffer.Length + sb.Length;
            if (needlen > buffer.MaxLength)//buf扩容
            {
                //计算新的capacity
                var newcapa = buffer.MaxLength * 2;//尝试x2
                if (newcapa < needlen)
                {
                    newcapa = needlen + buffer.MaxLength;//还是不够，就needlen+max
                }

                //产生newbuf
                var newbuf = StringNoGC.Create(newcapa, buffer.IsTemp);
                newbuf.CopyFrom(ref buffer);

                //交换
                buffer.Free();
                buffer = newbuf;
            }
            buffer.ConcatStringBuilder(sb);
        }

        #endregion

        #region AppendAnyFormat
        public void AppendFormat(string format, object arg0)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.AppendFormat(format, arg0);
            AppendStringBuilder(bridgesb);
        }
        public void AppendFormat(string format, object arg0, object arg1)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.AppendFormat(format, arg0, arg1);
            AppendStringBuilder(bridgesb);
        }
        public void AppendFormat(string format, object arg0, object arg1, object arg2)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.AppendFormat(format, arg0, arg1, arg2);
            AppendStringBuilder(bridgesb);
        }
        public void AppendFormat(string format, params object[] args)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.AppendFormat(format, args);
            AppendStringBuilder(bridgesb);
        }
        public void AppendFormat(ref StringNoGC format, object arg0)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.AppendFormat(format.ToStringNoGC(), arg0);
            AppendStringBuilder(bridgesb);
        }
        public void AppendFormat(ref StringNoGC format, object arg0, object arg1)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.AppendFormat(format.ToStringNoGC(), arg0, arg1);
            AppendStringBuilder(bridgesb);
        }
        public void AppendFormat(ref StringNoGC format, object arg0, object arg1, object arg2)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.AppendFormat(format.ToStringNoGC(), arg0, arg1, arg2);
            AppendStringBuilder(bridgesb);
        }
        public void AppendFormat(ref StringNoGC format, params object[] args)
        {
            if (bridgesb == null)
            {
                bridgesb = new StringBuilder(256);

            }
            bridgesb.Clear();
            bridgesb.AppendFormat(format.ToStringNoGC(), args);
            AppendStringBuilder(bridgesb);
        }

        #endregion
        #region ToString
        public override string ToString()
        {
            throw new Exception("ToString 有歧义，禁用。");
        }
        /// <summary>
        ///  //这个方法会clone一份产生一个 System.String.产生GC，但是一定是安全的
        /// </summary>
        /// <returns></returns>
        public string ToStringSystem()
        {
            //这个方法会clone一份产生一个 System.String 产生GC，但是一定是安全的
            return buffer.ToString();
        }
        /// <summary>
        /// //这个方法不产生GC，直接得到buffer 绑定的string，但这个string 可能会被改变，或者销毁，使用需要小心
        /// </summary>
        /// <returns></returns>
        public string ToStringNoGC()
        {
            return buffer.ToStringNoGC();
        }
        #endregion

    }
}
